
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define ARRAY_SIZE(x)   (sizeof(x) / sizeof((x)[0]))
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define member_size(TYPE, MEMBER) (sizeof((TYPE *)0)->MEMBER)

struct info {
    const char *type;
    const char *member;
    size_t      offset;
    size_t      size;
};


// #define __attr       __attribute__((aligned(4)))
// #define __attr       __attribute__((aligned(8)))
// #define __attr       __attribute__((aligned(32)))
#define __attr       __attribute__((aligned(1024)))

// #define __attr       __attribute__((aligned(1024 * 1024 * 1024)))

// #define __attr       __attribute__((packed))
// #define __attr       __attribute__((packed, aligned(4)))
// #define __attr       __attribute__((packed, aligned(1024)))

#ifndef __attr
#define __attr
#endif

struct test_struct {
    unsigned char   c_1;
    unsigned int    i_1;
    unsigned long   l_1;
    unsigned short  s_1;
    unsigned int    i_2;
    unsigned long   l_2;
    unsigned char   ca_1[3];
    unsigned short  s_2;
    unsigned int    i_3;
    unsigned char   ca_2[5];
    struct test_struct *priv;
    struct test_struct *next;
    unsigned char   c_3;
    unsigned int    i_4;
    unsigned short  s_3;
} __attr;


#define __to_info(TYPE, MEMBER) \
    {#TYPE, #MEMBER, offsetof(TYPE, MEMBER), member_size(TYPE, MEMBER),}

static const struct info st_infos[] = {
    __to_info(struct test_struct, c_1),
    __to_info(struct test_struct, i_1),
    __to_info(struct test_struct, l_1),
    __to_info(struct test_struct, s_1),
    __to_info(struct test_struct, i_2),
    __to_info(struct test_struct, l_2),
    __to_info(struct test_struct, ca_1),
    __to_info(struct test_struct, s_2),
    __to_info(struct test_struct, i_3),
    __to_info(struct test_struct, ca_2),
    __to_info(struct test_struct, priv),
    __to_info(struct test_struct, next),
    __to_info(struct test_struct, c_3),
    __to_info(struct test_struct, i_4),
    __to_info(struct test_struct, s_3),
};


typedef unsigned long long bit_t;

#define BITS_NUM            (8 * sizeof(bit_t))
#define MAP_LEN(stsize)     ((stsize + BITS_NUM - 1) / BITS_NUM)

static inline void set_bit(bit_t *p, unsigned int n)
{
    *(p + (n / BITS_NUM)) |= (1 << (n % BITS_NUM));
}

static inline unsigned int test_bit(bit_t *p, unsigned int n)
{
    return *(p + (n / BITS_NUM)) & (1 << (n % BITS_NUM));
}

static void print_st_info(const struct info *infos, size_t len, size_t st_size, unsigned int align_line)
{
    unsigned int i, j;

    printf("%20s %10s   %4s    %4s  %4s\n",
           "type", "member",
           "start", "end", "size");
    for (i = 0; i < (21 + 11 + 2 + 5 + 4 + 6 + 4); i++) {
        printf("_");
    }
    printf("\n");

    for (i = 0; i < len; i++) {
        const struct info *p = &infos[i];
        printf("%20s %10s : 0x%02X --> 0x%02X, 0x%02X\n",
               p->type, p->member,
               p->offset, p->offset + p->size, p->size);
    }
    for (i = 0; i < (21 + 11 + 2 + 5 + 4 + 6 + 4); i++) {
        printf("_");
    }
    printf("\n");
}

static void print_st_bitmap(const struct info *infos, size_t len, size_t st_size, unsigned int align_line)
{
    unsigned int i, j;
    size_t hole = 0;
    size_t data_size = 0;
    bit_t *map;

    if (align_line > 16) {
        align_line = 16;
    }

    map = malloc(MAP_LEN(st_size) * sizeof(bit_t));
    if (!map) {
        printf("no memory\n");
        return;
    }
    memset(map, 0x00, sizeof(map));
    for (i = 0; i < len; i++) {
        const struct info *p = &infos[i];
        data_size += p->size;
        for (j = p->offset; j < p->offset + p->size; j++) {
            set_bit(map, j);
        }
    }

    printf("   |");
    for (i = 0; i < align_line; i++) {
        printf(" %X", i);
    }
    printf(" |\n");

    for (i = 0; i < st_size; i++) {
        if (i >= (j + align_line - 1) / align_line * align_line) {
            printf("    ... ...\n");
            break;
        }
        if (0 == i % align_line) {
            printf("%3X|", i);
        }
        printf(" %s", test_bit(map, i) ? "*" : " ");
        if (align_line - 1 == i % align_line) {
            printf(" |\n");
        }
    }
    if (i == st_size && st_size % align_line) {
        printf(" |\n");
    }
    printf("total size: %u(0x%X), data size: %u(0x%X), hole size: %u(0x%X)\n",
            st_size, st_size, data_size, data_size, st_size - data_size, st_size - data_size);
    free(map);
}

int main(void)
{
    printf("info:\n");
    print_st_info(&st_infos[0], ARRAY_SIZE(st_infos), sizeof(struct test_struct), 16);

    printf("bitmap:\n");
    print_st_bitmap(&st_infos[0], ARRAY_SIZE(st_infos), sizeof(struct test_struct), 16);

    return 0;
}
